BaseBuffEffect = {};
BaseBuffEffect.__index = BaseBuffEffect;

function BaseBuffEffect:new()
    local object = {};
    setmetatable(object, BaseBuffEffect);
    return object;
end

function BaseBuffEffect:add(fight, buff)
    local effect = false;
    local buffBean = buff.buffBean;
    if buffBean.f_Atribute ~= "" then
        local attrBuff = decodeJsonStrToTabel(buffBean.f_Atribute);
        local attrids = attrBuff;
        for i = 1, #attrids do
            buff.value[attrids[i][1]] = attrids[i][2];
        end
        effect = true;
    end

    if buffBean.f_BuffSpecialEffect ~= "" then
        local stateids = decodeJsonStrToTabel(buffBean.f_BuffSpecialEffect);
        for i = 1, #stateids do
            local stateeff = ZZMathBit.lShiftOp(1, stateids[i] - 1);
            buff.state.state = ZZMathBit.orOp(buff.state.state, stateeff);
        end
        effect = true;
    end

    if buffBean.f_Tag ~= "" then
        local sign = decodeJsonStrToTabel(buffBean.f_Tag);
        for i = 1, #sign do
            buff.sign.signs[sign[i]] = true;
        end

        local target = buff.target;
        --移除此人身上所有标记互斥BUFF
        local buffs = {};
        for i = 1, #target.buffs do
            table.insert(buffs, target.buffs[i]);
        end
        if #buffs > 0 then
            for k, v in pairs(buffs) do
                local buff_exclusion = decodeJsonStrToTabel(v.buffBean.f_Exclusion);
                local buff_tag = decodeJsonStrToTabel(buff.buffBean.f_Tag);
                if inArray(buff_exclusion, buff_tag) then
                    fightLog("[BUFF]" .. target.fighterId .. "因为标记互斥被移除buff" .. v.modelId);
                    BuffManager.removeFighterBuff(fight, target, v, v.addParameter);
                end
            end
        end

        effect = true;
    end
    if effect then
        fightLog("[EFFECT]添加BUFF效果" .. buff.modelId);
    end

    return EnumConst.IBuffEffect.SUCCESS;
end

function BaseBuffEffect:action(fight, buff, ...)
    local buffBean = buff.buffBean;

    -- 移除时机 == 0或==17的时候触发后移除
    --[[
     * 这里是因为buff触发类型中有添加buff时触发
     * 下面代码中有触发时添加其他buff，此时buff未移除，可能会导致重复触发
     * 所以添加标记只触发一次
    ]]
    --[[
    if not buff.permanent and (buffBean.f_BuffRemoveTrigger == EnumConst.FightEventEnum.NONE or buffBean.f_BuffRemoveTrigger == EnumConst.FightEventEnum.TRIGGER_BUFF) then
        if buff.triggered then
            return EnumConst.IBuffEffect.FAIL;
        end
    end
    buff.triggered = true;
    ]]

    if buffBean.f_AddBuff ~= "" then
        fightLog("[EFFECT]" .. buff.modelId .. "触发增加BUFF效果");

        local buffids = decodeJsonStrToTabel(buffBean.f_AddBuff);
        for i = 1, #buffids do
            local addBuffBean = G.dataTable["t_buff"][tostring(buffids[i][1])];
            if buffBean == nil then
                fightLog("[BUFF]BUFFADD发生错误, Buff " .. buffids[i][1] .. "不存在");
                return EnumConst.IBuffEffect.FAIL;
            end
            local target = select('1', ...);
            if target == nil or addBuffBean.f_Target == EnumConst.BuffTargetTypeEnum.PARENT then
                target = buff.target;
            end

            BuffManager.addBuff(fight, buff.source, target, false, buffids[i][1], buffids[i][2], buff.addParameter);
        end
    end

    -- 永久BUFF
    if buff.permanent then
        return EnumConst.IBuffEffect.SUCCESS;
    end

    -- 移除时机 == 0或==17的时候触发后移除
    if buffBean.f_BuffRemoveTrigger == EnumConst.FightEventEnum.NONE or buffBean.f_BuffRemoveTrigger == EnumConst.FightEventEnum.TRIGGER_BUFF then
        return EnumConst.IBuffEffect.REMOVE;
    end
    return EnumConst.IBuffEffect.SUCCESS;
end

function BaseBuffEffect:remove(fight, buff, ...)
    return EnumConst.IBuffEffect.SUCCESS;
end

function BaseBuffEffect:resetAttribute(fight, buff)
    buff.value = {};
    local bufffBean = buff.buffBean;
    if bufffBean.f_Atribute ~= "" then
        local buffValue = bufffBean.f_Atribute;
        for i = 1, #buffValue do
            buff.value[buffValue[i][1]] = buffValue[i][2];
        end
        return true;
    end
    return false;
end

function BaseBuffEffect:addAttribute(fight, buff, attribute, startIndex)
    if attribute ~= nil then
        if buff.value[attribute[startIndex]] ~= nil then
            buff.value[attribute[startIndex]] = buff.value[attribute[startIndex]] + attribute[startIndex + 1];
        else
            buff.value[attribute[startIndex]] = attribute[startIndex + 1];
        end
    end
end

function BaseBuffEffect:inArray(array, values)
    if array == nil or values == nil then
        return false;
    end
    for k, v in pairs(array) do
        for k1, v1 in pairs(values) do
            if v == v1 then
                return true;
            end
        end
    end
    return false;
end

--[[**
* 触发技能
* 
* @param skill
]]
function BaseBuffEffect:triggerSkill(fight, fighter, target, triggerSkill)
    -- 生成基础触发技能信息
    local fskill = FightSkillManager.createFightSkill(fight, triggerSkill);
    if fskill == nil then
        return ;
    end

    -- 触发技能选择目标
    target = FightSkillManager.selectAttackTarget(fight, fighter, fskill, fighter.position, nil);
    if target == nil then
        return ;
    end

    --[[for i=1,#target do
        log(target[i].fighterId);
    end--]]

    local usingSkill = FightUsingSkill.New();
    usingSkill.fight = fight;
    usingSkill.fighter = fighter;
    usingSkill.target = target;
    usingSkill.skill = fskill;
    table.insert(fight.skills, usingSkill);

    if fskill.skillBean.f_SkillOut == 1 then
        -- 技能加速速度
        local speed = tonumber(fskill.skillBean.f_Speed) / EnumConst.TEN_THOUSANDTH;
        if speed > 0 then
            if fskill.skillShow ~= nil then
                local vSpeed = Vector3.Normalize(Vector3(target.position.x, 300, target.position.y) - Vector3(skill.position.x, 300, skill.position.y));
                local distance = Vector3.Distance(Vector3(target.position.x, 300, target.position.y), Vector3(skill.position.x, 300, skill.position.y));
                vSpeed = vSpeed * speed;
                fighter:playFly(fskill.skillShow, vSpeed, distance / speed, fskill.position);
            end
        else
            if fskill.skillShow ~= nil then
                target:playFly(fskill.skillShow, nil, 0, fskill.position);
            end
        end
    else
        fighter:playSkill(fskill.skillBean, fskill.skillShow, target);
    end

    -- 如果非分离技能，打断所有正在使用的非分离技能
    if fskill.skillBean.f_SkillOut ~= 1 and fighter.usingSkill ~= nil then
        FightDamageManager.finishSkill(fighter.usingSkill, true);
    end

    fightLog("[SKILL]" .. fighter.fighterId .. "对" .. target.fighterId .. "BUFF触发技能" .. fskill.skillBean.f_SkillID);

    -- 开始释放技能
    FightDamageManager.prepareSkill(usingSkill, fighter.position);
end

--[[
* 根据buff影响范围获取目标
* @param centerPos 范围中心点
* TODO: 2020/11/2 wangjunhui 待实现 buff表需加字段 (有没有必要加?)
]]
function BaseBuffEffect:getEffectTargetsByRange(fight, buff, buffOwner, centerPos, ...)
    local parameters = {...};
    --LogUtil.info(fight, ()-> String.format("[%s][BUFF]%s范围影响寻找目标,中心点%s",
    --fight.getFrame(), buff.getModelId(), centerPos));

    local targes = {};
    --TODO: 2020/11/2 wangjunhui --------↓↓↓↓↓↓↓↓↓↓↓↓↓↓---------- 暂时写死 后面配表
    --目标阵营
    local effectTargetCamp = 1;
    -- buff影响范围
    local shape = Rectangle2:New(2, 2);
    --TODO: 2020/11/2 wangjunhui --------↑↑↑↑↑↑↑↑↑↑↑↑↑↑---------- 暂时写死 后面配表
    local fightTeam = fight.teams[effectTargetCamp];
    for k, f in (fightTeam.fighters) do
        if (f:isDie()) then
            goto continue;
        end
        if (not DistanceUtil.overlap(centerPos, shape, f.position, f.shape)) then
            goto continue;
        end
        -- TODO: 2020/11/2 判断各种特殊状态能不能被选为目标
        targes.add(f);
        SkillRoleMgr.savePathFile(string.format("[%s][BUFF]%s范围影响寻找到目标%s,位置为%s",
                fight.frame, buff.modelId, f.fighterId, f.position)
        );
    end
    return targes;
end

--[[
* action触发是否是由伤害 前/后   被伤害 前/后  触发的,
* 这种类型又附加调用 {@link com.game.fight.manager.DamageManager#realDamage(Fight, Fighter, Fighter, int, FightResult, int)}
* 如果没有中断机制,就会造成死循环
* @param buff
* @return
]]
function BaseBuffEffect:isDamageActionTrigger(buff)
    local actionTrigger = buff.buffBean.f_BuffActionTrigger;
    return actionTrigger == FightEventEnum.BEFORE_DAMAGE or actionTrigger == FightEventEnum.BEFORE_BE_DAMAGE
            or actionTrigger == FightEventEnum.AFTER_DAMAGE or actionTrigger == FightEventEnum.AFTER_BE_DAMAGE;
end